home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / cubezip.exe / CUBE.ASM next >
Assembly Source File  |  1991-10-15  |  30KB  |  609 lines

  1. include macros.h
  2. ;╒══════════════════════════════════════════════════════════════════════════╕
  3. ;│                                        │
  4. ;│     CUBE  - A general purpose solver of combinatorial block puzzles        │
  5. ;│                                        │
  6. ;│               written by: Steve Gibson                    │
  7. ;│                           Gibson Research Corporation            │
  8. ;│                           9/18/91                        │
  9. ;│                                        │
  10. ;│     Please note: These files were asssembled and linked with Steve        │
  11. ;│     Russell's excellent optimizing assembler (OPTASM) and linker        │
  12. ;│     (OPTLINK). Consequently, if any "conditional jump out-of-range"        │
  13. ;│     errors are received either the files will have to be edited or        │
  14. ;│     an optimizing assembler will have to be used.                │
  15. ;│                                                       - ENJOY!        │
  16. ;│                                        │
  17. ;╘══════════════════════════════════════════════════════════════════════════╛
  18.  
  19.     TITLE    CUBE
  20.  
  21. ;╒══════════════════════════════════════════════════════════════════════════╕
  22. ;│                                        │
  23. ;│       CUBE solves Bob's wooden block puzzle.                    │
  24. ;│                                        │
  25. ;│       ────────────────────────────────────────────────────────────────   │
  26. ;│       Please see the READ.ME and TECHTALK.TXT files that were included   │
  27. ;│       within the CUBE.EXE self-extracting ZIP file for further details   │
  28. ;│       about the CUBE ... and for information about where you can        │ 
  29. ;│       purchase the cube puzzle if you'd like to play with it yourself    │ 
  30. ;│       and assemble it from the program's result.                │
  31. ;│       ────────────────────────────────────────────────────────────────   │
  32. ;│                                        │
  33. ;│       This puzzle consists of a 3x3x3 "master cube" composed of 27        │
  34. ;│       "sub-cubes."  Combinations of sub-cubes are stuck together        │
  35. ;│       forming the nine puzzle pieces.  The puzzle is complicated        │
  36. ;│       by the fact that a number of the sub-cubes are cut half, with        │
  37. ;│       different halves stuck to different pieces. This means that        │
  38. ;│       rotating the pieces requires both rotation and translation of        │
  39. ;│       the sub-cubes, rather than just translation as would be the        │
  40. ;│       case if all of the sub-cubes were simple cubes.            │ 
  41. ;│                                        │
  42. ;│       Numbering and Axis legend:                        │
  43. ;│       ─────────────────────────────────────────────────────────────        │
  44. ;│       Individual pieces are numbered 0 thru 8.                │
  45. ;│       Positions within the master 3x3x3 cube are numbered 1 thru 27.        │
  46. ;│       Corners of the 2x2x2 sub-cubes are numbered 1 thru 8.            │
  47. ;│       The X axis runs left-to-right through the master cube.            │
  48. ;│       The Y axis runs into and outof the table.                │
  49. ;│       The Z axis runs forward and backward through the master cube.        │
  50. ;│       A positive X rotation flops the cube forward.                │
  51. ;│       A positive Y rotation twists the cube 90 degrees clockwise.        │
  52. ;│       A positive Z rotation flops the cube to the right.            │
  53. ;│                                        │
  54. ;╘══════════════════════════════════════════════════════════════════════════╛
  55.  
  56.  
  57. ;┌──────────────────────────────────────────────────────────────────────────┐
  58. ;│  ****************  E Q U A T E S   A N D   M A C R O S  ***************  │
  59. ;└──────────────────────────────────────────────────────────────────────────┘
  60.  
  61. NUMBER_OF_PIECES    equ    9    ; puzzle contains nine pieces
  62. CUBE_LENGTH        equ    3
  63. CUBE_HEIGHT        equ    3
  64. CUBE_DEPTH        equ    3
  65. CUBE_SURFACE        equ    CUBE_LENGTH * CUBE_HEIGHT
  66. SUB_CUBE_COUNT        equ    CUBE_LENGTH * CUBE_HEIGHT * CUBE_DEPTH
  67. PIECE_DEFINITION_LENGTH    equ    (OFFSET Piece_2 - OFFSET Piece_1)
  68.  
  69. ;┌──────────────────────────────────────────────────────────────────────────┐
  70. ;│ ***************************  S E G M E N T S  ************************** │
  71. ;└──────────────────────────────────────────────────────────────────────────┘
  72. CodeSeg        segment para public 'code'
  73.         assume    cs: CodeSeg, ds: CodeSeg, es: CodeSeg, ss: CodeSeg
  74.  
  75. ;┌──────────────────────────────────────────────────────────────────────────┐
  76. ;│ ***********************  E N T R Y    P O I N T  *********************** │  
  77. ;└──────────────────────────────────────────────────────────────────────────┘
  78.         org    0
  79. StartOfProg    equ    THIS BYTE
  80.         org    100h
  81. Entry:        jmp    SolveIt
  82.  
  83. ;┌──────────────────────────────────────────────────────────────────────────┐
  84. ;│ *****************  P U Z Z L E    P I E C E    D A T A  **************** │
  85. ;└──────────────────────────────────────────────────────────────────────────┘
  86.  
  87. PieceDefinitions:
  88. ;┌──────────────────────────────────────────────────────────────────────────┐
  89. ;│       The piece definitions specify the shape of the individual        │
  90. ;│       pieces, and their initial position parity. Each of the first        │
  91. ;│       five bytes represents a single sub-cube, with each of the        │
  92. ;│       byte's 8-bits representing wood in the respective corner of        │
  93. ;│       the sub-cube. Thus FF represents a solid cube and AA, CC,        │
  94. ;│       and F0 represents various orientations of half-cubes.  ZERO        │
  95. ;│       parity means Dark Wood at the 1,1,1 corner (the first byte)        │
  96. ;│       of the cube's definition.                        │
  97. ;│──────────────────────────────────────────────────────────────────────────│
  98. ;│               1     2     3     4     5     6    Color Parity            │
  99. ;└──────────────────────────────────────────────────────────────────────────┘
  100. Piece_1   db    0FFh, 0FFh, 0FFh, 0CCh, 000h, 000h, 0    ; L: short foot
  101. Piece_2   db    0FFh, 0FFh, 0AAh, 000h,    000h, 0AAh, 0    ; short L with thin foot
  102. Piece_3   db    0FFh, 0FFh, 000h, 0FFh,    000h, 000h, 0    ; elbow 1
  103. Piece_4   db    0FFh, 0FFh, 000h, 0FFh,    000h, 000h, 1    ; elbow 2
  104. Piece_5   db    0FFh, 0FFh, 0AAh, 00Fh,    000h, 000h, 0    ; short L with twisted foot
  105. Piece_6   db    0FFh, 0FFh, 00Fh, 0CCh,    000h, 000h, 0    ; L: twist head & short foot
  106. Piece_7   db    0FFh, 0FFh, 00Fh, 000h,    000h, 000h, 1    ; I: twisted head
  107. Piece_8   db    0FFh, 0FFh, 0F0h, 0CCh,    000h, 000h, 0    ; L: lifted twist hd, shrt ft
  108. Piece_9   db    0FFh, 0FFh, 0CCh, 000h, 0F0h, 000h, 0    ; T: twist head, lifted stem
  109.  
  110.  
  111. ;┌──────────────────────────────────────────────────────────────────────────┐
  112. ;│       These Spin Tables manage the rotation of the 2x2x2 sub-cubes        │
  113. ;│       within the larger 3x3x3 master cube. Each sub-cube contains        │
  114. ;│       eight items, representing wood in each of its eight corners.        │
  115. ;│       Each table consists of 8 bytes, where the ON bit in the byte        │
  116. ;│       specifies where the bit mapped into the byte will move when        │
  117. ;│       the 2x2x2 cube is subjected to a positive rotation about the        │
  118. ;│       specified axis.                            │
  119. ;│                                        │
  120. ;│       Destination:   12345678   12345678   12345678   12345678        │
  121. ;└──────────────────────────────────────────────────────────────────────────┘
  122. Spin_X_Table    db    00001000b, 00000100b, 10000000b, 01000000b
  123.         db    00000010b, 00000001b, 00100000b, 00010000b
  124. ;────────────────────────────────────────────────────────────────────────────
  125. Spin_Y_Table    db    01000000b, 00010000b, 10000000b, 00100000b
  126.         db    00000100b, 00000001b, 00001000b, 00000010b
  127. ;────────────────────────────────────────────────────────────────────────────
  128. Spin_Z_Table    db    01000000b, 00000100b, 00010000b, 00000001b
  129.         db    10000000b, 00001000b, 00100000b, 00000010b
  130.  
  131. ;┌──────────────────────────────────────────────────────────────────────────┐
  132. ;│       These Rotate Tables manage the translation of the 2x2x2        │
  133. ;│       sub-cubes within the larger 3x3x3 master cube. When the        │
  134. ;│       master cube is rotated each of the sub-cubes is rotated        │
  135. ;│       based upon the Spin tables above, then the sub-cube is            │
  136. ;│       translated, relocating its position within the 3x3x3 master        │
  137. ;│       cube. Each entry in the table below specifies which one of        │
  138. ;│       the 27 sub-cubes will occupy the respective location            │
  139. ;│       within the new master cube after rotation.                │
  140. ;└──────────────────────────────────────────────────────────────────────────┘
  141. Rotate_X_Table    db    7,  8,  9, 16, 17, 18, 25, 26, 27    ;  1- 9
  142.         db    4,  5,  6, 13, 14, 15, 22, 23, 24    ; 10-18
  143.         db    1,  2,  3, 10, 11, 12, 19, 20, 21    ; 19-27
  144. ;────────────────────────────────────────────────────────────────────────────
  145. Rotate_Y_Table    db    7,  4,  1,  8,  5,  2,  9,  6,  3    ;  1- 9
  146.         db    16, 13, 10, 17, 14, 11, 18, 15, 12    ; 10-18
  147.         db    25, 22, 19, 26, 23, 20, 27, 24, 21    ; 19-27
  148. ;────────────────────────────────────────────────────────────────────────────
  149. Rotate_Z_Table    db    19, 10,  1, 22, 13,  4, 25, 16,  7    ;  1- 9
  150.         db    20, 11,  2, 23, 14,  5, 26, 17,  8    ; 10-18
  151.         db    21, 12,  3, 24, 15,  6, 27, 18,  9    ; 19-27
  152.  
  153.  
  154. ;┌──────────────────────────────────────────────────────────────────────────┐
  155. ;│    These Translation Tables manage the translation of the sub-cubes        │
  156. ;│    within the larger 3x3x3 master cube. When the master cube is        │
  157. ;│    translated, each of the sub-cubes is relocated within the 3x3x3        │
  158. ;│    master cube. Each entry in the table below specifies which one of        │
  159. ;│    the 27 sub-cubes will occupy the respective location within the        │
  160. ;│    new master cube after translation.  A ZERO entry means that the        │
  161. ;│    location will be completely empty after translation.            │
  162. ;└──────────────────────────────────────────────────────────────────────────┘
  163. Translate_X0_Table  db     2,  3,  0,  5,  6,  0,  8,  9,  0    ;  1- 9
  164.             db    11, 12,  0, 14, 15,  0, 17, 18,  0    ; 10-18
  165.             db  20, 21,  0, 23, 24,  0, 26, 27,  0    ; 19-27
  166. ;────────────────────────────────────────────────────────────────────────────
  167. Translate_X1_Table  db     0,  1,  2,  0,  4,  5,  0,  7,  8    ;  1- 9
  168.             db     0, 10, 11,  0, 13, 14,  0, 16, 17    ; 10-18
  169.             db     0, 19, 20,  0, 22, 23,  0, 25, 26    ; 19-27
  170. ;────────────────────────────────────────────────────────────────────────────
  171. Translate_Y0_Table  db    10, 11, 12, 13, 14, 15, 16, 17, 18    ;  1- 9
  172.             db    19, 20, 21, 22, 23, 24, 25, 26, 27    ; 10-18
  173.             db     0,  0,  0,  0,  0,  0,  0,  0,  0    ; 19-27
  174. ;────────────────────────────────────────────────────────────────────────────
  175. Translate_Y1_Table  db     0,  0,  0,  0,  0,  0,  0,  0,  0    ;  1- 9
  176.             db     1,  2,  3,  4,  5,  6,  7,  8,  9    ; 10-18
  177.             db    10, 11, 12, 13, 14, 15, 16, 17, 18    ; 19-27
  178. ;────────────────────────────────────────────────────────────────────────────
  179. Translate_Z0_Table  db   4,  5,  6,  7,  8,  9,  0,  0,  0    ;  1- 9
  180.             db    13, 14, 15, 16, 17, 18,  0,  0,  0    ; 10-18
  181.             db    22, 23, 24, 25, 26, 27,  0,  0,  0    ; 19-27
  182. ;────────────────────────────────────────────────────────────────────────────
  183. Translate_Z1_Table  db     0,  0,  0,  1,  2,  3,  4,  5,  6    ;  1- 9
  184.             db     0,  0,  0, 10, 11, 12, 13, 14, 15    ; 10-18
  185.             db     0,  0,  0, 19, 20, 21, 22, 23, 24    ; 19-27
  186.  
  187. ;┌──────────────────────────────────────────────────────────────────────────┐
  188. ;│    These Surface Tables specify which sub-cubes lie upon each of the        │
  189. ;│    six surfaces of the master cube.  This is used by the translation        │
  190. ;│    logic to determine whether an object may be translated into the        │
  191. ;│    empty surface of the master cube.  Each table lists the nine sub-        │
  192. ;│    cubes lying on the respecting face of the master cube.            │
  193. ;└──────────────────────────────────────────────────────────────────────────┘
  194. Surface_X0_Table   db      1,  4,  7, 10, 13, 16, 19, 22, 25
  195. Surface_X1_Table   db      3,  6,  9, 12, 15, 18, 21, 24, 27
  196. ;────────────────────────────────────────────────────────────────────────────
  197. Surface_Y0_Table   db      1,  2,  3,  4,  5,  6,  7,  8,  9
  198. Surface_Y1_Table   db     19, 20, 21, 22, 23, 24, 25, 26, 27
  199. ;────────────────────────────────────────────────────────────────────────────
  200. Surface_Z0_Table   db      1,  2,  3, 10, 11, 12, 19, 20, 21
  201. Surface_Z1_Table   db      7,  8,  9, 16, 17, 18, 25, 26, 27
  202.  
  203.  
  204. ;┌──────────────────────────────────────────────────────────────────────────┐
  205. ;│ ************  M I S C E L L A N E O U S   V A R I A B L E S ************ │
  206. ;└──────────────────────────────────────────────────────────────────────────┘
  207.  
  208. ;┌──────────────────────────────────────────────────────────────────────────┐
  209. ;│  Indexed by piece number [0..8] This is a table of the number of images  │
  210. ;│  we've generated for each piece.  The image generator increments these   │
  211. ;│  values as it stores non-redundant piece images, and the tree exploring  │
  212. ;│  routine uses this to explore the resulting image tables.            │
  213. ;└──────────────────────────────────────────────────────────────────────────┘
  214. PieceImageCounts    dw    NUMBER_OF_PIECES dup (0)
  215.  
  216. ;┌──────────────────────────────────────────────────────────────────────────┐
  217. ;│  Indexed by piece number [0..8] This is a table of OFFSETS into the        │
  218. ;│  PieceTable (but relative to DS) for each set of piece image tables.        │
  219. ;└──────────────────────────────────────────────────────────────────────────┘
  220. PieceTableOffsets    dw    NUMBER_OF_PIECES dup (0)
  221.  
  222. ;┌──────────────────────────────────────────────────────────────────────────┐
  223. ;│  This is the offset of the NEXT AVAILABLE BYTE in the PieceTable.        │
  224. ;│  Piece image tables are allocated from this point and it is augmented    │
  225. ;│  by the size of a table: SUB_CUBE_COUNT+1.                    │
  226. ;└──────────────────────────────────────────────────────────────────────────┘
  227. CurrentTableBase    dw    PieceTable    ; initialize at bottom
  228.  
  229. ;┌──────────────────────────────────────────────────────────────────────────┐
  230. ;│  These are general usage working piece storage tables.  The Working        │
  231. ;│  Piece Table contains the piece position we're currently operating upon. │
  232. ;└──────────────────────────────────────────────────────────────────────────┘
  233. WorkingPieceTable    db    SUB_CUBE_COUNT+1 dup(0)
  234. TempPieceTable        db    SUB_CUBE_COUNT+1 dup(0)
  235. XSaveTable        db    SUB_CUBE_COUNT+1 dup(0)
  236. YSaveTable        db    SUB_CUBE_COUNT+1 dup(0)
  237.  
  238. ;┌──────────────────────────────────────────────────────────────────────────┐
  239. ;│  The number of the Piece we're currently operating upon.            │
  240. ;└──────────────────────────────────────────────────────────────────────────┘
  241. CurrentPiece        dw    0
  242.  
  243.  
  244. ;┌──────────────────────────────────────────────────────────────────────────┐
  245. ;│ ********** S T A R T    O F    E X E C U T A B L E    C O D E ********** │
  246. ;└──────────────────────────────────────────────────────────────────────────┘
  247. SolveIt:    cld                ; initialize things ...
  248.         mov    sp, OFFSET TopOfStack    ; switch to internal stack
  249.         call    SetupTheSystem
  250.  
  251.         mov    CurrentPiece, 0        ; start with the first one
  252.  
  253. ;┌──────────────────────────────────────────────────────────────────────────┐
  254. ;│   We build all possible positions of each puzzle piece ... This is all   │
  255. ;│   24 orientations of each the piece in each translated location.        │ 
  256. ;└──────────────────────────────────────────────────────────────────────────┘
  257. ;┌──────────────────────────────────────────────────────────────────────────┐
  258. ;│   To process a piece, we load the piece's definition into the        │
  259. ;│   WorkingTable, then give it a good spin!                    │
  260. ;└──────────────────────────────────────────────────────────────────────────┘
  261. ProcessAPiece:    mov    ax, PIECE_DEFINITION_LENGTH    ; don't move parity
  262.         mov    bx, CurrentPiece
  263.         mov    cx, ax            ; save the length for the move
  264.         dec    cx            ; move one less than the len
  265.         mul    bx            ; get piece definition
  266.         add    ax, OFFSET PieceDefinitions
  267.         mov    si, ax
  268.         mov    di, OFFSET WorkingPieceTable
  269.         rep movsb            ; load the table
  270.         zero    al
  271.         mov    cx, SUB_CUBE_COUNT - (PIECE_DEFINITION_LENGTH - 1)
  272.         rep stosb            ; and clear the rest
  273.         movsb            ; add the parity to the end
  274.  
  275. ;┌──────────────────────────────────────────────────────────────────────────┐
  276. ;│       Now we save the CurrentTableBase as the base for this piece        │
  277. ;└──────────────────────────────────────────────────────────────────────────┘
  278.  
  279.         double    bx            ; turn piece into a word ptr
  280.         mov    ax, CurrentTableBase
  281.         mov    PieceTableOffsets[bx], ax
  282.         mov    PieceImageCounts[bx], 0        ; clear the count
  283.  
  284. ;┌──────────────────────────────────────────────────────────────────────────┐
  285. ;│       Now we store all 24 orientations of the piece in every            │
  286. ;│       translation. The sequence of orientation explorations is:        │
  287. ;│       3*(3*Y,X)  -<Y,X,X>-  3*(3*Y,X)                    │
  288. ;└──────────────────────────────────────────────────────────────────────────┘
  289.  
  290.         call    ExploreHalf    ; flesh out half the orientations
  291.             call    Rotate_Y    ; flip over to the second half
  292.         call    Rotate_X_Twice
  293.         call    ExploreHalf    ; and flesh out the second half
  294.  
  295. ;┌──────────────────────────────────────────────────────────────────────────┐
  296. ;│       Now we process the next piece ... if one exists            │
  297. ;└──────────────────────────────────────────────────────────────────────────┘
  298.         inc    CurrentPiece    ; [0..8]
  299.         cmp    CurrentPiece, NUMBER_OF_PIECES
  300.         jb    ProcessAPiece
  301.  
  302.  
  303. ;┌──────────────────────────────────────────────────────────────────────────┐
  304. ;│                No more pieces! ... so let's get to work!            │
  305. ;│          We'll exhaustively search through the entire tree ...        │
  306. ;└──────────────────────────────────────────────────────────────────────────┘
  307.         jmp    SearchTheTree
  308.  
  309. ;╒══════════════════════════════════════════════════════════════════════════╕
  310. ;│ ************************  S U B R O U T I N E S  *********************** │
  311. ;╘══════════════════════════════════════════════════════════════════════════╛
  312.  
  313. ;╒══════════════════════════════════════════════════════════════════════════╕
  314. ;│       This routine makes 12 calls to "StoreTranslations" with the        │
  315. ;│       puzzle piece in a different orientation each time.  It's        │
  316. ;│       called twice, once for each half of the possible orientations.        │
  317. ;│       The sequence of rotation calls is: 3*(3*Y,X)                │
  318. ;└──────────────────────────────────────────────────────────────────────────┘
  319. ExploreHalf:    mov    cx, 3
  320. MiddleLoop:    call    StoreAllTrans    ; store translations @ current orient
  321.         push    cx
  322.         mov    cx, 3
  323. ;────────────────────────────────────────────────────────────────────────────
  324. InnerLoop:    call    Rotate_Y
  325.         call    StoreAllTrans
  326.         loop    InnerLoop
  327.             call    Rotate_X
  328.         pop    cx
  329.         loop    MiddleLoop
  330.         ret
  331.  
  332.  
  333. ;╒══════════════════════════════════════════════════════════════════════════╕
  334. ;│  Given the current orientation of the current WorkingPiece, build legal  │
  335. ;│  translations, storing unique ones in the piece's position image table.  │
  336. ;└──────────────────────────────────────────────────────────────────────────┘
  337. StoreAllTrans:    push    cx
  338.         call    SlideToOrigin    ; push the piece -> X0, Y0, Z0
  339.         jmp    ExploreX
  340.  
  341. MoveOnX:    call    TranslateX1
  342. ExploreX:    mov    di, OFFSET XSaveTable
  343.         call    SavePieceState        ; stack the piece's location
  344.         jmp    ExploreY
  345. ;════════════════════════════════════════════════════════════════════════════
  346. MoveOnY:    call    TranslateY1
  347. ExploreY:    mov    di, OFFSET YSaveTable
  348.         call    SavePieceState        ; stack the piece's location
  349.         jmp    ExploreZ
  350.  
  351. ;────────────────────────────────────────────────────────────────────────────
  352. MoveOnZ:    call    TranslateZ1
  353. ExploreZ:    test    WorkingPieceTable[SUB_CUBE_COUNT], 1    ; check parity
  354.         jnz    SkipThisSave
  355.         call    StoreNewPosition
  356. SkipThisSave:    mov    bx, OFFSET Surface_Z1_Table
  357.         call    TestSurface
  358.         jz    MoveOnZ
  359. ;────────────────────────────────────────────────────────────────────────────
  360.         mov    si, OFFSET YSaveTable
  361.         call    RestorePieceState    ; recover the piece's loc.
  362.         mov    bx, OFFSET Surface_Y1_Table
  363.         call    TestSurface
  364.         jz    MoveOnY
  365. ;════════════════════════════════════════════════════════════════════════════
  366.         mov    si, OFFSET XSaveTable
  367.         call    RestorePieceState    ; recover the piece's loc.
  368.         mov    bx, OFFSET Surface_X1_Table
  369.         call    TestSurface
  370.         jz    MoveOnX
  371.         pop    cx
  372.         ret
  373.  
  374.  
  375. StoreNewPosition:
  376. ;╒══════════════════════════════════════════════════════════════════════════╕
  377. ;│       Save the unique position (from WorkingPositionTable) into        │
  378. ;│       the piece's position memory.                        │
  379. ;│                                        │
  380. ;│               ax - overall iteration counter                    │
  381. ;│               bx - destination renewal                    │
  382. ;│               cx - rep count                            │
  383. ;│               dx - rep save                            │
  384. ;│               si source index                        │
  385. ;│               di dest index                            │
  386. ;│               bp - source renewal                        │
  387. ;└──────────────────────────────────────────────────────────────────────────┘
  388.         mov    bx, CurrentPiece
  389.         double    bx                ; make word index
  390.         mov    ax, PieceImageCounts[bx]    ; get image count
  391.         mov    bx, PieceTableOffsets[bx]    ; get table base
  392.         mov    bp, OFFSET WorkingPieceTable    ; get source index
  393.         mov    dx, (SUB_CUBE_COUNT+1)/2    ; (14 compares)
  394.  
  395. ;────────────────────────────────────────────────────────────────────────────
  396. CheckForUnique:    mov    cx, dx        ; get the table size to compare
  397.         mov    si, bp        ; renew the source location
  398.         mov    di, bx        ; and get the table loc
  399.         check    ax        ; do we have any more?
  400.         jz    ItsUnique    ; nope, so move rather than compare
  401.  
  402.         repe cmpsw        ; are they the same?
  403.         je    NotUnique
  404.  
  405.         add    bx, dx
  406.         add    bx, dx        ; point to the next table
  407.         dec    ax        ; decrement the number remaining
  408.         jmp    CheckForUnique    ; check the next image
  409.  
  410.  
  411. ;────────────────────────────────────────────────────────────────────────────
  412. ItsUnique:    rep movsw            ; copy the new position ...
  413.         mov    CurrentTableBase, di    ; update the base pointer
  414.         mov    bx, CurrentPiece    ; get index
  415.         double    bx            ; make word index
  416.         inc    PieceImageCounts[bx]    ; and increment the count
  417.         call    ShowImageCount
  418. ;────────────────────────────────────────────────────────────────────────────
  419. NotUnique:    ret
  420.  
  421.  
  422. SavePieceState:
  423. ;╒══════════════════════════════════════════════════════════════════════════╕
  424. ;│                 Save the WorkingPieceTable piece state            │
  425. ;│                    in the table pointed to by [DI].                │
  426. ;└──────────────────────────────────────────────────────────────────────────┘
  427.         mov    si, OFFSET WorkingPieceTable
  428.         jmp    CopyPieceTable
  429.  
  430.  
  431. RestorePieceState:
  432. ;╒══════════════════════════════════════════════════════════════════════════╕
  433. ;│                 Restore the WorkingPieceTable piece state            │
  434. ;│                    from the table pointed to by [SI].            │
  435. ;└──────────────────────────────────────────────────────────────────────────┘
  436.         mov    di, OFFSET WorkingPieceTable
  437. CopyPieceTable:    mov    cx, (SUB_CUBE_COUNT+1)/2    ; move words
  438.         rep movsw
  439.         ret
  440.  
  441.  
  442. SlideToOrigin:    
  443. ;╒══════════════════════════════════════════════════════════════════════════╕
  444. ;│               Translate the current piece as far as it            │
  445. ;│               will go in the X0, Y0, and Z0 directions.            │
  446. ;└──────────────────────────────────────────────────────────────────────────┘
  447. SlideXBack:    mov    bx, OFFSET Surface_X0_Table
  448.         call    TestSurface
  449.         jnz    SlideYBack
  450.         call    TranslateX0
  451.         jmp    SlideXBack
  452. ;────────────────────────────────────────────────────────────────────────────
  453. SlideYBack:    mov    bx, OFFSET Surface_Y0_Table
  454.         call    TestSurface
  455.         jnz    SlideZBack
  456.         call    TranslateY0
  457.         jmp    SlideYBack
  458. ;────────────────────────────────────────────────────────────────────────────
  459. SlideZBack:    mov    bx, OFFSET Surface_Z0_Table
  460.         call    TestSurface
  461.         jnz    Originated
  462.         call    TranslateZ0
  463.         jmp    SlideZBack
  464. ;────────────────────────────────────────────────────────────────────────────
  465. Originated:    ret
  466.  
  467.  
  468. ;╒══════════════════════════════════════════════════════════════════════════╕
  469. ;│               These entry-points slide the puzzle piece one            │
  470. ;│               cube in the appropriate direction                │
  471. ;└──────────────────────────────────────────────────────────────────────────┘
  472. TranslateX0:    mov    bx, OFFSET Translate_X0_Table
  473.         jmp    ToggleParity
  474. TranslateX1:    mov    bx, OFFSET Translate_X1_Table
  475.         jmp    ToggleParity
  476. TranslateY0:    mov    bx, OFFSET Translate_Y0_Table
  477.         jmp    ToggleParity
  478. TranslateY1:    mov    bx, OFFSET Translate_Y1_Table
  479.         jmp    ToggleParity
  480. TranslateZ0:    mov    bx, OFFSET Translate_Z0_Table
  481.         jmp    ToggleParity
  482. TranslateZ1:    mov    bx, OFFSET Translate_Z1_Table
  483.         jmp    ToggleParity
  484.  
  485. ;────────────────────────────────────────────────────────────────────────────
  486. Rotate_X_Twice:    Call    Rotate_X            ; execute below twice
  487. ;╒══════════════════════════════════════════════════════════════════════════╕
  488. ;│               Flop the WorkingPiece definition forward            │
  489. ;│             The X axis runs left-to-right through the cube            │
  490. ;└──────────────────────────────────────────────────────────────────────────┘
  491. Rotate_X:    mov    bx, OFFSET Spin_X_Table        ; the X spin spec
  492.         call    SpinCubes            ; spin individuals
  493.         mov    bx, OFFSET Rotate_X_Table    ; the X rotate spec
  494.         jmp    MoveCubes
  495.  
  496. ;╒══════════════════════════════════════════════════════════════════════════╕
  497. ;│              Twist the WorkingPiece definition clockwise            │
  498. ;│             The Y axis runs top-to-bottom through the cube            │
  499. ;└──────────────────────────────────────────────────────────────────────────┘
  500. Rotate_Y:    mov    bx, OFFSET Spin_Y_Table        ; the X spin spec
  501.         call    SpinCubes            ; spin individuals
  502.         mov    bx, OFFSET Rotate_Y_Table    ; the X rotate spec
  503.         jmp    MoveCubes
  504.  
  505. ;╒══════════════════════════════════════════════════════════════════════════╕
  506. ;│             Flop the WorkingPiece definition to the right            │
  507. ;│             The Z axis runs front-to-back through the cube            │
  508. ;└──────────────────────────────────────────────────────────────────────────┘
  509. Rotate_Z:    mov    bx, OFFSET Spin_Z_Table        ; the X spin spec
  510.         call    SpinCubes            ; spin individuals
  511.         mov    bx, OFFSET Rotate_Z_Table    ; the X rotate spec
  512.         jmp    MoveCubes
  513.  
  514.  
  515. ToggleParity:
  516. ;╒══════════════════════════════════════════════════════════════════════════╕
  517. ;│                   This entry to MoveCubes toggles the            │
  518. ;│                   parity bit in the WorkingPieceTable            │
  519. ;└──────────────────────────────────────────────────────────────────────────┘
  520.         xor    WorkingPieceTable[SUB_CUBE_COUNT], 1    ; toggle bit
  521. ;╒══════════════════════════════════════════════════════════════════════════╕
  522. ;│            Rotate the WorkingPiece sub-cubes about the central        │
  523. ;│              axis using the rotation table pointed to by BX            │
  524. ;└──────────────────────────────────────────────────────────────────────────┘
  525. MoveCubes:    push    cx
  526.         mov    cx, SUB_CUBE_COUNT
  527.         mov    di, OFFSET TempPieceTable
  528.         push    di        ; save temp piece table location
  529. ;────────────────────────────────────────────────────────────────────────────
  530. NextCube:    mov    si, [bx]    ; get the item to move
  531.         and    si, 00FFh    ; the index is byte size
  532.         mov    al, WorkingPieceTable[si-1]    ; 0-base it
  533.         jnz    MoveCube    ; did we get a zero?
  534.         zero    al        ; yep, so clear the block...
  535. MoveCube:    stosb            ; save the new piece definition
  536.         inc    bx        ; point to next table entry
  537.         loop    NextCube
  538. ;────────────────────────────────────────────────────────────────────────────
  539.         mov    cx, SUB_CUBE_COUNT
  540.         pop    si        ; recover the temp piece location
  541.         mov    di, OFFSET WorkingPieceTable
  542.         rep movsb        ; and copy the temp -> piece
  543.         pop    cx
  544.         ret
  545.  
  546.  
  547. ;╒══════════════════════════════════════════════════════════════════════════╕
  548. ;│            Spin the individual WorkingPiece sub-cubes about            │
  549. ;│           their own axis using the spin table pointed to by BX        │
  550. ;└──────────────────────────────────────────────────────────────────────────┘
  551. SpinCubes:    push    cx
  552.         mov    di, OFFSET WorkingPieceTable
  553.         mov    cx, SUB_CUBE_COUNT
  554. SpinCorner:    push    cx        ; save cube counter
  555.         mov    ah, [di]    ; get the cube's bits
  556.         zero    al        ; zero result catcher
  557.         mov    cx, 8        ; spin 8 bits
  558. DoCorner:    shl    ah, 1        ; get the next bit
  559.         jnc    NextCorner
  560.         or    al, [bx]    ; or in the bit specified
  561. NextCorner:    inc    bx        ; get next mask
  562.         loop    DoCorner    ; and do eight of them
  563.         stosb            ; save the result and inc ...
  564.         sub    bx, 8        ; and re-point BX to the table
  565.         pop    cx        ; recover the cube counter
  566.         loop    SpinCorner
  567.         pop    cx
  568.         ret
  569.  
  570.  
  571.  
  572. ;╒══════════════════════════════════════════════════════════════════════════╕
  573. ;│       Test the WorkingPieceTable for "wood" along the surface        │
  574. ;│       specified in the table pointed to by BX, return with FLAGS        │
  575. ;└──────────────────────────────────────────────────────────────────────────┘
  576. TestSurface:    mov    ax, 00FFh        ; byte mask
  577.         mov    cx, CUBE_SURFACE    ; nine sub-cubes on surface
  578. ;────────────────────────────────────────────────────────────────────────────
  579. NextSubCube:    mov    si, [bx]    ; get the item to move
  580.         and    si, ax        ; the index is only a byte long
  581.         test    BYTE PTR WorkingPieceTable[si-1], al ; check for wood
  582.         jnz    SurfaceTested
  583.         inc    bx        ; prepare for the next one
  584.         loop    NextSubCube
  585.         zero    cx        ; set flags to "ZERO"
  586. SurfaceTested:    ret
  587.  
  588.  
  589. WaitForKeypress:
  590. ;╒══════════════════════════════════════════════════════════════════════════╕
  591. ;│       Waits for a keypress from the keyboard ...                │
  592. ;└──────────────────────────────────────────────────────────────────────────┘
  593.         mov    ah, GETKEY_WAIT
  594.         int    KEYBOARD_IO
  595.         ret
  596.  
  597. ;────────────────────────────────────────────────────────────────────────────
  598. include cubesys.inc    ; include the cube screen file here
  599. include cubesrch.inc    ; include the cube search algorithm
  600. ;════════════════════════════════════════════════════════════════════════════
  601. InitScreenBuffer    = THIS BYTE
  602. PieceTable        = InitScreenBuffer + SCREEN_LENGTH
  603. BottomOfStack        = PieceTable + (SUB_CUBE_COUNT+1) * (8*72+96)
  604. TopOfStack        = BottomOfStack + STACK_DEPTH
  605. ;════════════════════════════════════════════════════════════════════════════
  606. CodeSeg        ends
  607.         end    Entry
  608.  
  609.